/**
 * 
 */
package org.rollinitiative.d20web.gmportal.server;

import java.util.ArrayList;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.TreeSet;
import java.util.UUID;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.rollinitiative.d20.combat.Initiative;
import org.rollinitiative.d20.encounter.Combatant;
import org.rollinitiative.d20.encounter.Encounter;
import org.rollinitiative.d20.encounter.Faction;
import org.rollinitiative.d20.entity.Actor;
import org.rollinitiative.d20.entity.HitPoints;
import org.rollinitiative.d20.entity.NonPlayer;
import org.rollinitiative.d20web.gmportal.client.CombatantData;
import org.rollinitiative.d20web.gmportal.client.EncounterService;

import com.google.gwt.user.server.rpc.RemoteServiceServlet;
import com.sun.corba.se.spi.orbutil.fsm.Action;
import com.sun.org.apache.bcel.internal.generic.NEW;

/**
 * @author bebopjmm
 * 
 */
public class EncounterServiceImpl extends RemoteServiceServlet implements EncounterService
{
    private static final Log LOG = LogFactory.getLog(EncounterService.class);

    private Encounter currentEncounter;

    private Hashtable<UUID, Encounter> encounterTable = new Hashtable<UUID, Encounter>();


    /*
     * (non-Javadoc)
     * 
     * @see org.rollinitiative.d20web.gmportal.client.EncounterService#getParty(java.lang.String)
     */
    public String[] getParty(String campaign)
    {
        // TODO Auto-generated method stub
        return null;
    }


    public String createNewEncounter(String encounterName)
    {
        UUID encounterID = UUID.randomUUID();
        encounterTable.put(encounterID, new Encounter(encounterName));
        LOG.info("Created new encounter with UUID: " + encounterID.toString());
        return encounterID.toString();
    }


    /*
     * (non-Javadoc)
     * 
     * @see
     * org.rollinitiative.d20web.gmportal.client.EncounterService#addCombatant(java.lang.String,
     * java.lang.String, int)
     */
    public CombatantData addCombatant(String encounterID, String actorName, int faction)
    {
        LOG.debug("EncounterID for combatant being added: " + encounterID);
        UUID id = UUID.fromString(encounterID);
        Encounter encounter = encounterTable.get(id);

        LOG.info("Adding new combatant to encounter, name = " + actorName);
        CombatantData results = new CombatantData();
        Combatant newCombatant = null;

        Actor newActor = new NonPlayer(actorName);
        switch (faction) {
        case PARTY_FACTION:
            newCombatant = encounter.joinEncounter(newActor, Faction.PARTY, false);
            break;

        case HOSTILES_FACTION:
            newCombatant = encounter.joinEncounter(newActor, Faction.HOSTILE, false);
            break;

        case NEUTRALS_FACTION:
            newCombatant = encounter.joinEncounter(newActor, Faction.NEUTRAL, false);
            break;

        case ALLIES_FACTION:
            newCombatant = encounter.joinEncounter(newActor, Faction.ALLY, false);
            break;

        default:
            LOG.error("Unsupported faction value: " + faction);
            return results;
        }
        results.setCombatantName(newCombatant.getActor().getName());
        results.setCombatantUUID(newActor.getActorID().toString());
        results.setFactionName(newCombatant.getAllegiance().toString());
        results.setAware(false);
        results.setInitiativeMod(-1);
        results.setInitiativeBase(-1);
        results.setHitPoints(0);

        return results;
    }


    /*
     * (non-Javadoc)
     * 
     * @see
     * org.rollinitiative.d20web.gmportal.client.EncounterService#initiateCombatant(org.rollinitiative
     * .d20web.gmportal.client.CombatantData)
     */
    public CombatantData[] combatantAware(String encounterID, CombatantData combatantData)
    {
        UUID id = UUID.fromString(encounterID);
        Encounter encounter = encounterTable.get(id);

        LOG.info("Initiating combatant... name = " + combatantData.getCombatantName()
                + "\n-- initBase=" + combatantData.getInitiativeBase() + "\n-- initMod="
                + combatantData.getInitiativeMod() + "\n-- hitPoints="
                + combatantData.getHitPoints());

        UUID actorID = UUID.fromString(combatantData.getCombatantUUID());
        Combatant combatant = encounter.getCombatant(actorID);
        
        Initiative init = combatant.getInitiative();
        // FIXME temp hack until initiative mod's can be pulled directly from actor.
        init.setFixedMod(combatantData.getInitiativeMod());

        if (combatantData.getInitiativeBase() < 0) {
            combatant.makeAware();
        }
        else {
            combatant.makeAware(combatantData.getInitiativeBase());
        }

//        init = combatant.getInitiative();
//        combatantData.setInitiativeBase(init.getBaseRoll());
//        combatantData.setInitiativeMod(init.getModifier());
//        combatantData.setInitiativeVal(init.getValue());
//        LOG.info("Total Initiative Value for, " + combatantData.getCombatantName() + " = "
//                + combatantData.getInitiativeVal());

        // FIXME Temporary HACK to inject hit points until linked to real actor data.
        HitPoints hitPoints = new HitPoints(combatantData.getHitPoints(), false);
        NonPlayer actor = (NonPlayer) combatant.getActor();
        actor.setHitPoints(hitPoints);

        // TODO Return the full set of combatants in initiative order
        encounter.makeCombatantAware(UUID.fromString(combatantData.getCombatantUUID()));

        Combatant[] order = encounter.getInitiativeOrder();
        CombatantData[] results = new CombatantData[order.length];
        for (int i = 0; i < results.length; i++) {
            LOG.info("name/initBase: " + order[i].getActor().getName() + "/"
                    + order[i].getInitiative().getBaseRoll());
            results[i] = new CombatantData();
            results[i].setAware(true);
            results[i].setCombatantName(order[i].getActor().getName());
            results[i].setCombatantUUID(order[i].getActor().getActorID().toString());
            results[i].setFactionName(order[i].getAllegiance().toString());
            results[i].setHitPoints(order[i].getActor().getHitPoints().getCurrentHP());
            results[i].setInitiativeBase(order[i].getInitiative().getBaseRoll());
            results[i].setInitiativeMod(order[i].getInitiative().getModifier());
            results[i].setInitiativeVal(order[i].getInitiative().getValue());
        }
        return results;
    }


    /*
     * (non-Javadoc)
     * 
     * @see
     * org.rollinitiative.d20web.gmportal.client.EncounterService#rollInitiative(org.rollinitiative
     * .d20web.gmportal.client.CombatantData)
     */
    public CombatantData rollInitiative(String encounterID, CombatantData combatant)
    {
        // TODO Auto-generated method stub
        return null;
    }


    /*
     * (non-Javadoc)
     * 
     * @see
     * org.rollinitiative.d20web.gmportal.client.EncounterService#startEncounter(java.lang.String)
     */
    public void startEncounter(String encounterID)
    {
        UUID id = UUID.fromString(encounterID);
        Encounter encounter = encounterTable.get(id);

    }


    /*
     * (non-Javadoc)
     * 
     * @see
     * org.rollinitiative.d20web.gmportal.client.EncounterService#getNextCombatant(java.lang.String)
     */
    public CombatantData getNextCombatant(String encounterID)
    {
        UUID id = UUID.fromString(encounterID);
        Encounter encounter = encounterTable.get(id);

        return null;
    }

}
